"""
备牙数据学习曲线分析工具 - 现代化GUI界面
Advanced Visual Learning Curve Analyzer

特点：
- 现代化的Material Design风格界面
- 支持深色/浅色主题切换
- 实时数据预览和交互式图表
- 专业的数据分析和可视化功能
"""

import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import tkinter.font as tkFont
import os
import sys
import threading
import json
from datetime import datetime
import webbrowser

try:
    import matplotlib.pyplot as plt
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
    from matplotlib.figure import Figure
    import matplotlib.style as mplstyle
    import numpy as np
    import pandas as pd
    DEPENDENCIES_OK = True
except ImportError as e:
    DEPENDENCIES_OK = False
    MISSING_DEPS = str(e)

# 导入原有的分析模块
try:
    from curve_calc_all import (
        calculate_learning_curve, 
        calculate_learning_rate, 
        read_data_from_csv,
        plot_learning_curves,
        plot_average_learning_curves
    )
    from extractor import extract_groups_to_csv
    MODULES_OK = True
except ImportError as e:
    MODULES_OK = False
    MISSING_MODULES = str(e)


class MaterialColors:
    """Material Design配色方案"""
    # 浅色主题
    LIGHT = {
        'primary': '#1976D2',
        'primary_dark': '#1565C0', 
        'primary_light': '#42A5F5',
        'secondary': '#FF5722',
        'secondary_dark': '#E64A19',
        'secondary_light': '#FF8A65',
        'background': '#FAFAFA',
        'surface': '#FFFFFF',
        'error': '#F44336',
        'success': '#4CAF50',
        'warning': '#FF9800',
        'info': '#2196F3',
        'text_primary': '#212121',
        'text_secondary': '#757575',
        'text_disabled': '#BDBDBD',
        'divider': '#E0E0E0'
    }
    
    # 深色主题
    DARK = {
        'primary': '#2196F3',
        'primary_dark': '#1976D2',
        'primary_light': '#64B5F6',
        'secondary': '#FF5722',
        'secondary_dark': '#E64A19',
        'secondary_light': '#FF8A65',
        'background': '#121212',
        'surface': '#1E1E1E',
        'error': '#CF6679',
        'success': '#81C784',
        'warning': '#FFB74D',
        'info': '#64B5F6',
        'text_primary': '#FFFFFF',
        'text_secondary': '#B3B3B3',
        'text_disabled': '#666666',
        'divider': '#333333'
    }


class ModernButton(tk.Button):
    """现代化按钮组件"""
    def __init__(self, parent, text="", command=None, style="primary", **kwargs):
        self.style_type = style
        self.parent = parent
        
        # 获取主题颜色
        if hasattr(parent, 'theme_colors'):
            colors = parent.theme_colors
        else:
            colors = MaterialColors.LIGHT
        
        # 设置样式
        if style == "primary":
            bg_color = colors['primary']
            fg_color = colors['text_primary'] if 'dark' in str(colors) else '#FFFFFF'
            hover_color = colors['primary_dark']
        elif style == "secondary":
            bg_color = colors['secondary']
            fg_color = '#FFFFFF'
            hover_color = colors['secondary_dark']
        elif style == "success":
            bg_color = colors['success']
            fg_color = '#FFFFFF'
            hover_color = '#45A049'
        else:
            bg_color = colors['surface']
            fg_color = colors['text_primary']
            hover_color = colors['divider']
        
        super().__init__(
            parent,
            text=text,
            command=command,
            bg=bg_color,
            fg=fg_color,
            relief='flat',
            bd=0,
            padx=20,
            pady=10,
            font=('Microsoft YaHei UI', 10, 'bold'),
            cursor='hand2',
            **kwargs
        )
        
        # 悬停效果
        self.hover_color = hover_color
        self.original_color = bg_color
        
        self.bind('<Enter>', self.on_enter)
        self.bind('<Leave>', self.on_leave)
    
    def on_enter(self, e):
        self.config(bg=self.hover_color)
    
    def on_leave(self, e):
        self.config(bg=self.original_color)


class ModernCard(tk.Frame):
    """现代化卡片组件"""
    def __init__(self, parent, title="", **kwargs):
        colors = getattr(parent, 'theme_colors', MaterialColors.LIGHT)
        
        super().__init__(
            parent,
            bg=colors['surface'],
            relief='flat',
            bd=1,
            **kwargs
        )
        
        if title:
            title_label = tk.Label(
                self,
                text=title,
                font=('Microsoft YaHei UI', 12, 'bold'),
                fg=colors['text_primary'],
                bg=colors['surface']
            )
            title_label.pack(anchor='w', padx=15, pady=(15, 5))


class LearningCurveAnalyzer:
    """主应用程序类"""
    
    def __init__(self, root):
        self.root = root
        self.theme_colors = MaterialColors.LIGHT
        self.current_theme = "light"
        
        # 检查依赖
        if not DEPENDENCIES_OK:
            self.show_dependency_error()
            return
        
        if not MODULES_OK:
            self.show_module_error()
            return
        
        self.setup_window()
        self.setup_matplotlib()
        self.create_interface()
        self.load_settings()
        
    def show_dependency_error(self):
        """显示依赖错误"""
        error_window = tk.Toplevel(self.root)
        error_window.title("依赖错误")
        error_window.geometry("500x300")
        error_window.resizable(False, False)
        
        tk.Label(error_window, 
                text="缺少必要的依赖包",
                font=('Microsoft YaHei UI', 14, 'bold'),
                fg='red').pack(pady=20)
        
        tk.Label(error_window,
                text="请运行以下命令安装依赖：",
                font=('Microsoft YaHei UI', 10)).pack(pady=10)
        
        command_text = tk.Text(error_window, height=3, width=60)
        command_text.pack(pady=10)
        command_text.insert('1.0', "pip install matplotlib pandas numpy openpyxl")
        command_text.config(state='disabled')
        
        tk.Button(error_window, 
                 text="运行安装脚本",
                 command=self.run_install_script).pack(pady=10)
        
        tk.Button(error_window, 
                 text="退出",
                 command=self.root.quit).pack(pady=5)
    
    def show_module_error(self):
        """显示模块错误"""
        messagebox.showerror("模块错误", 
                           f"无法导入分析模块：{MISSING_MODULES}\n\n"
                           "请确保 curve_calc_all.py 和 extractor.py 文件在当前目录中。")
        self.root.quit()
    
    def run_install_script(self):
        """运行安装脚本"""
        try:
            if os.name == 'nt':  # Windows
                os.system("install_dependencies.bat")
            else:  # Unix/Linux/Mac
                os.system("bash install_dependencies.sh")
            messagebox.showinfo("提示", "安装完成，请重启程序。")
        except Exception as e:
            messagebox.showerror("错误", f"安装失败：{str(e)}")
        finally:
            self.root.quit()
    
    def setup_window(self):
        """设置主窗口"""
        self.root.title("备牙数据学习曲线分析工具 v2.0 - Professional Edition")
        self.root.geometry("1400x900")
        self.root.minsize(1200, 700)
        
        # 设置窗口居中
        self.center_window()
        
        # 设置图标
        self.setup_icon()
        
        # 应用主题
        self.apply_theme()
    
    def center_window(self):
        """窗口居中"""
        self.root.update_idletasks()
        x = (self.root.winfo_screenwidth() // 2) - (1400 // 2)
        y = (self.root.winfo_screenheight() // 2) - (900 // 2)
        self.root.geometry(f"1400x900+{x}+{y}")
    
    def setup_icon(self):
        """设置窗口图标"""
        try:
            # 如果有图标文件
            if os.path.exists('icon.ico'):
                self.root.iconbitmap('icon.ico')
        except:
            pass
    
    def apply_theme(self):
        """应用主题"""
        colors = self.theme_colors
        self.root.configure(bg=colors['background'])
        
        # 设置ttk样式
        style = ttk.Style()
        style.theme_use('clam')
        
        # 配置各种组件样式
        style.configure('Title.TLabel',
                       font=('Microsoft YaHei UI', 18, 'bold'),
                       foreground=colors['primary'],
                       background=colors['background'])
        
        style.configure('Subtitle.TLabel',
                       font=('Microsoft YaHei UI', 12, 'bold'),
                       foreground=colors['text_primary'],
                       background=colors['background'])
        
        style.configure('Card.TFrame',
                       background=colors['surface'],
                       relief='flat',
                       borderwidth=1)
    
    def setup_matplotlib(self):
        """设置matplotlib样式"""
        plt.style.use('default')
        plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei', 'Arial']
        plt.rcParams['axes.unicode_minus'] = False
        plt.rcParams['figure.facecolor'] = 'white'
        plt.rcParams['axes.facecolor'] = 'white'
    
    def create_interface(self):
        """创建界面"""
        # 创建顶部工具栏
        self.create_toolbar()
        
        # 创建主内容区域
        self.create_main_content()
        
        # 创建状态栏
        self.create_status_bar()
        
        # 创建侧边栏
        self.create_sidebar()
    
    def create_toolbar(self):
        """创建顶部工具栏"""
        toolbar = tk.Frame(self.root, bg=self.theme_colors['primary'], height=60)
        toolbar.pack(fill='x')
        toolbar.pack_propagate(False)
        
        # 应用标题
        title_frame = tk.Frame(toolbar, bg=self.theme_colors['primary'])
        title_frame.pack(side='left', fill='y', padx=20)
        
        app_title = tk.Label(title_frame,
                            text="📊 备牙数据学习曲线分析工具",
                            font=('Microsoft YaHei UI', 16, 'bold'),
                            fg='white',
                            bg=self.theme_colors['primary'])
        app_title.pack(expand=True)
        
        # 工具栏按钮
        button_frame = tk.Frame(toolbar, bg=self.theme_colors['primary'])
        button_frame.pack(side='right', fill='y', padx=20)
        
        # 主题切换按钮
        theme_btn = tk.Button(button_frame,
                             text="🌙" if self.current_theme == "light" else "☀️",
                             command=self.toggle_theme,
                             bg=self.theme_colors['primary_dark'],
                             fg='white',
                             relief='flat',
                             bd=0,
                             padx=15,
                             pady=5,
                             font=('Arial', 12),
                             cursor='hand2')
        theme_btn.pack(side='right', padx=5, pady=15)
        
        # 帮助按钮
        help_btn = tk.Button(button_frame,
                            text="❓",
                            command=self.show_help,
                            bg=self.theme_colors['primary_dark'],
                            fg='white',
                            relief='flat',
                            bd=0,
                            padx=15,
                            pady=5,
                            font=('Arial', 12),
                            cursor='hand2')
        help_btn.pack(side='right', padx=5, pady=15)
    
    def create_sidebar(self):
        """创建侧边栏"""
        self.sidebar = tk.Frame(self.root, 
                               bg=self.theme_colors['surface'],
                               width=300)
        self.sidebar.pack(side='left', fill='y', padx=(0, 10), pady=10)
        self.sidebar.pack_propagate(False)
        
        # 侧边栏标题
        sidebar_title = tk.Label(self.sidebar,
                                text="📁 数据管理",
                                font=('Microsoft YaHei UI', 14, 'bold'),
                                fg=self.theme_colors['text_primary'],
                                bg=self.theme_colors['surface'])
        sidebar_title.pack(pady=(20, 15))
        
        # 文件选择区域
        self.create_file_selection()
        
        # 分析设置区域
        self.create_analysis_settings()
        
        # 执行按钮
        self.create_action_buttons()
    
    def create_file_selection(self):
        """创建文件选择区域"""
        file_card = ModernCard(self.sidebar, title="文件选择")
        file_card.pack(fill='x', padx=15, pady=(0, 15))
        
        # Excel文件选择
        excel_frame = tk.Frame(file_card, bg=self.theme_colors['surface'])
        excel_frame.pack(fill='x', padx=15, pady=10)
        
        tk.Label(excel_frame,
                text="Excel源文件:",
                font=('Microsoft YaHei UI', 10),
                fg=self.theme_colors['text_primary'],
                bg=self.theme_colors['surface']).pack(anchor='w')
        
        excel_input_frame = tk.Frame(excel_frame, bg=self.theme_colors['surface'])
        excel_input_frame.pack(fill='x', pady=(5, 0))
        
        self.excel_path_var = tk.StringVar()
        excel_entry = tk.Entry(excel_input_frame,
                              textvariable=self.excel_path_var,
                              font=('Microsoft YaHei UI', 9),
                              bg='white',
                              relief='flat',
                              bd=1)
        excel_entry.pack(side='left', fill='x', expand=True)
        
        excel_browse_btn = ModernButton(excel_input_frame,
                                       text="📂",
                                       command=self.browse_excel_file,
                                       style="secondary")
        excel_browse_btn.pack(side='right', padx=(5, 0))
        
        # 工作表选择
        sheet_frame = tk.Frame(file_card, bg=self.theme_colors['surface'])
        sheet_frame.pack(fill='x', padx=15, pady=10)
        
        tk.Label(sheet_frame,
                text="工作表:",
                font=('Microsoft YaHei UI', 10),
                fg=self.theme_colors['text_primary'],
                bg=self.theme_colors['surface']).pack(anchor='w')
        
        self.sheet_var = tk.StringVar()
        self.sheet_combo = ttk.Combobox(sheet_frame,
                                       textvariable=self.sheet_var,
                                       font=('Microsoft YaHei UI', 9),
                                       state='readonly')
        self.sheet_combo.pack(fill='x', pady=(5, 0))
        
        # 提取按钮
        extract_btn = ModernButton(file_card,
                                  text="📊 提取数据",
                                  command=self.extract_excel_data,
                                  style="primary")
        extract_btn.pack(pady=15)
        
        # CSV文件路径
        csv_frame = tk.Frame(file_card, bg=self.theme_colors['surface'])
        csv_frame.pack(fill='x', padx=15, pady=10)
        
        # IR组文件
        tk.Label(csv_frame,
                text="IR组数据:",
                font=('Microsoft YaHei UI', 10),
                fg=self.theme_colors['text_primary'],
                bg=self.theme_colors['surface']).pack(anchor='w')
        
        ir_input_frame = tk.Frame(csv_frame, bg=self.theme_colors['surface'])
        ir_input_frame.pack(fill='x', pady=(5, 0))
        
        self.ir_path_var = tk.StringVar(value="IR组.csv")
        ir_entry = tk.Entry(ir_input_frame,
                           textvariable=self.ir_path_var,
                           font=('Microsoft YaHei UI', 9),
                           bg='white',
                           relief='flat',
                           bd=1)
        ir_entry.pack(side='left', fill='x', expand=True)
        
        ir_browse_btn = ModernButton(ir_input_frame,
                                    text="📂",
                                    command=lambda: self.browse_csv_file(self.ir_path_var),
                                    style="secondary")
        ir_browse_btn.pack(side='right', padx=(5, 0))
        
        # MR组文件
        tk.Label(csv_frame,
                text="MR组数据:",
                font=('Microsoft YaHei UI', 10),
                fg=self.theme_colors['text_primary'],
                bg=self.theme_colors['surface']).pack(anchor='w', pady=(10, 0))
        
        mr_input_frame = tk.Frame(csv_frame, bg=self.theme_colors['surface'])
        mr_input_frame.pack(fill='x', pady=(5, 0))
        
        self.mr_path_var = tk.StringVar(value="MR组.csv")
        mr_entry = tk.Entry(mr_input_frame,
                           textvariable=self.mr_path_var,
                           font=('Microsoft YaHei UI', 9),
                           bg='white',
                           relief='flat',
                           bd=1)
        mr_entry.pack(side='left', fill='x', expand=True)
        
        mr_browse_btn = ModernButton(mr_input_frame,
                                    text="📂",
                                    command=lambda: self.browse_csv_file(self.mr_path_var),
                                    style="secondary")
        mr_browse_btn.pack(side='right', padx=(5, 0))
    
    def create_analysis_settings(self):
        """创建分析设置区域"""
        settings_card = ModernCard(self.sidebar, title="分析设置")
        settings_card.pack(fill='x', padx=15, pady=(0, 15))
        
        # 分析模式
        mode_frame = tk.Frame(settings_card, bg=self.theme_colors['surface'])
        mode_frame.pack(fill='x', padx=15, pady=10)
        
        tk.Label(mode_frame,
                text="分析模式:",
                font=('Microsoft YaHei UI', 10, 'bold'),
                fg=self.theme_colors['text_primary'],
                bg=self.theme_colors['surface']).pack(anchor='w')
        
        self.analysis_mode = tk.StringVar(value="single")
        
        single_radio = tk.Radiobutton(mode_frame,
                                     text="单组预测分析",
                                     variable=self.analysis_mode,
                                     value="single",
                                     font=('Microsoft YaHei UI', 9),
                                     fg=self.theme_colors['text_primary'],
                                     bg=self.theme_colors['surface'],
                                     selectcolor=self.theme_colors['primary'])
        single_radio.pack(anchor='w', pady=2)
        
        compare_radio = tk.Radiobutton(mode_frame,
                                      text="两组对比分析",
                                      variable=self.analysis_mode,
                                      value="compare",
                                      font=('Microsoft YaHei UI', 9),
                                      fg=self.theme_colors['text_primary'],
                                      bg=self.theme_colors['surface'],
                                      selectcolor=self.theme_colors['primary'])
        compare_radio.pack(anchor='w', pady=2)
        
        # 分析参数
        params_frame = tk.Frame(settings_card, bg=self.theme_colors['surface'])
        params_frame.pack(fill='x', padx=15, pady=10)
        
        # 最大训练次数
        tk.Label(params_frame,
                text="最大训练次数:",
                font=('Microsoft YaHei UI', 10),
                fg=self.theme_colors['text_primary'],
                bg=self.theme_colors['surface']).pack(anchor='w')
        
        self.max_training_var = tk.IntVar(value=30)
        training_spinbox = tk.Spinbox(params_frame,
                                     from_=10, to=100,
                                     textvariable=self.max_training_var,
                                     font=('Microsoft YaHei UI', 9),
                                     width=15)
        training_spinbox.pack(anchor='w', pady=(5, 0))
        
        # 图表标题
        tk.Label(params_frame,
                text="图表标题:",
                font=('Microsoft YaHei UI', 10),
                fg=self.theme_colors['text_primary'],
                bg=self.theme_colors['surface']).pack(anchor='w', pady=(10, 0))
        
        self.chart_title_var = tk.StringVar()
        title_entry = tk.Entry(params_frame,
                              textvariable=self.chart_title_var,
                              font=('Microsoft YaHei UI', 9),
                              bg='white',
                              relief='flat',
                              bd=1)
        title_entry.pack(fill='x', pady=(5, 0))
    
    def create_action_buttons(self):
        """创建操作按钮"""
        # 主要执行按钮
        self.analyze_btn = ModernButton(self.sidebar,
                                       text="🚀 开始分析",
                                       command=self.run_analysis,
                                       style="success")
        self.analyze_btn.pack(fill='x', padx=15, pady=10)
        
        # 进度条
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(self.sidebar,
                                           variable=self.progress_var,
                                           mode='determinate')
        # 初始隐藏进度条
        
        # 次要按钮
        button_frame = tk.Frame(self.sidebar, bg=self.theme_colors['surface'])
        button_frame.pack(fill='x', padx=15, pady=5)
        
        preview_btn = ModernButton(button_frame,
                                  text="👁️ 预览数据",
                                  command=self.preview_data)
        preview_btn.pack(fill='x', pady=2)
        
        clear_btn = ModernButton(button_frame,
                                text="🗑️ 清空结果",
                                command=self.clear_results)
        clear_btn.pack(fill='x', pady=2)
    
    def create_main_content(self):
        """创建主内容区域"""
        # 内容容器
        content_frame = tk.Frame(self.root, bg=self.theme_colors['background'])
        content_frame.pack(side='right', fill='both', expand=True, padx=10, pady=10)
        
        # 创建notebook
        self.notebook = ttk.Notebook(content_frame)
        self.notebook.pack(fill='both', expand=True)
        
        # 可视化标签页
        self.create_visualization_tab()
        
        # 数据预览标签页
        self.create_data_tab()
        
        # 结果分析标签页
        self.create_results_tab()
    
    def create_visualization_tab(self):
        """创建可视化标签页"""
        viz_frame = ttk.Frame(self.notebook)
        self.notebook.add(viz_frame, text="📊 可视化图表")
        
        # 工具栏
        toolbar = tk.Frame(viz_frame, bg=self.theme_colors['surface'], height=50)
        toolbar.pack(fill='x')
        toolbar.pack_propagate(False)
        
        # 工具栏按钮
        ModernButton(toolbar, text="💾 保存图表", 
                    command=self.save_plot).pack(side='left', padx=10, pady=10)
        
        ModernButton(toolbar, text="🔄 刷新", 
                    command=self.refresh_plot).pack(side='left', padx=5, pady=10)
        
        ModernButton(toolbar, text="⚙️ 图表设置", 
                    command=self.show_plot_settings).pack(side='left', padx=5, pady=10)
        
        # 图表区域
        chart_frame = tk.Frame(viz_frame, bg='white')
        chart_frame.pack(fill='both', expand=True, padx=10, pady=10)
        
        # 创建matplotlib图表
        self.figure = Figure(figsize=(12, 8), dpi=100, facecolor='white')
        self.canvas = FigureCanvasTkAgg(self.figure, chart_frame)
        self.canvas.get_tk_widget().pack(fill='both', expand=True)
        
        # 初始化空图表
        self.init_empty_plot()
    
    def create_data_tab(self):
        """创建数据预览标签页"""
        data_frame = ttk.Frame(self.notebook)
        self.notebook.add(data_frame, text="📋 数据预览")
        
        # 控制面板
        control_panel = tk.Frame(data_frame, bg=self.theme_colors['surface'], height=50)
        control_panel.pack(fill='x')
        control_panel.pack_propagate(False)
        
        ModernButton(control_panel, text="📊 预览IR组", 
                    command=lambda: self.preview_csv_data('ir')).pack(side='left', padx=10, pady=10)
        
        ModernButton(control_panel, text="📊 预览MR组", 
                    command=lambda: self.preview_csv_data('mr')).pack(side='left', padx=5, pady=10)
        
        ModernButton(control_panel, text="🗑️ 清空", 
                    command=self.clear_data_preview).pack(side='right', padx=10, pady=10)
        
        # 数据预览区域
        preview_frame = tk.Frame(data_frame, bg=self.theme_colors['background'])
        preview_frame.pack(fill='both', expand=True, padx=10, pady=10)
        
        # Treeview用于显示数据
        tree_frame = tk.Frame(preview_frame)
        tree_frame.pack(fill='both', expand=True)
        
        # 滚动条
        v_scrollbar = ttk.Scrollbar(tree_frame)
        v_scrollbar.pack(side='right', fill='y')
        
        h_scrollbar = ttk.Scrollbar(tree_frame, orient='horizontal')
        h_scrollbar.pack(side='bottom', fill='x')
        
        # 数据表格
        self.data_tree = ttk.Treeview(tree_frame,
                                     yscrollcommand=v_scrollbar.set,
                                     xscrollcommand=h_scrollbar.set)
        self.data_tree.pack(fill='both', expand=True)
        
        v_scrollbar.config(command=self.data_tree.yview)
        h_scrollbar.config(command=self.data_tree.xview)
    
    def create_results_tab(self):
        """创建结果分析标签页"""
        results_frame = ttk.Frame(self.notebook)
        self.notebook.add(results_frame, text="📈 分析结果")
        
        # 结果展示区域
        self.results_text = tk.Text(results_frame,
                                   font=('Consolas', 10),
                                   bg='white',
                                   fg='black',
                                   wrap='word')
        
        # 滚动条
        results_scroll = ttk.Scrollbar(results_frame)
        results_scroll.pack(side='right', fill='y')
        
        self.results_text.pack(fill='both', expand=True, padx=10, pady=10)
        results_scroll.config(command=self.results_text.yview)
        self.results_text.config(yscrollcommand=results_scroll.set)
        
        # 初始内容
        self.results_text.insert('1.0', "尚未进行分析，请先选择数据文件并点击开始分析按钮。")
        self.results_text.config(state='disabled')
    
    def create_status_bar(self):
        """创建状态栏"""
        status_frame = tk.Frame(self.root, bg=self.theme_colors['primary'], height=30)
        status_frame.pack(fill='x', side='bottom')
        status_frame.pack_propagate(False)
        
        self.status_var = tk.StringVar(value="就绪")
        status_label = tk.Label(status_frame,
                               textvariable=self.status_var,
                               font=('Microsoft YaHei UI', 9),
                               fg='white',
                               bg=self.theme_colors['primary'])
        status_label.pack(side='left', padx=15, pady=5)
        
        # 时间显示
        self.time_var = tk.StringVar()
        time_label = tk.Label(status_frame,
                             textvariable=self.time_var,
                             font=('Microsoft YaHei UI', 9),
                             fg='white',
                             bg=self.theme_colors['primary'])
        time_label.pack(side='right', padx=15, pady=5)
        
        self.update_time()
    
    def update_time(self):
        """更新时间"""
        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.time_var.set(current_time)
        self.root.after(1000, self.update_time)
    
    def update_status(self, message):
        """更新状态"""
        self.status_var.set(message)
        self.root.update_idletasks()
    
    # 事件处理方法
    def toggle_theme(self):
        """切换主题"""
        if self.current_theme == "light":
            self.theme_colors = MaterialColors.DARK
            self.current_theme = "dark"
        else:
            self.theme_colors = MaterialColors.LIGHT
            self.current_theme = "light"
        
        # 重新应用主题
        self.apply_theme()
        # 这里可以添加更多主题切换逻辑
    
    def show_help(self):
        """显示帮助"""
        help_window = tk.Toplevel(self.root)
        help_window.title("使用帮助")
        help_window.geometry("600x500")
        help_window.resizable(False, False)
        
        help_text = """
备牙数据学习曲线分析工具 - 使用指南

📋 基本功能：
1. Excel数据提取：从Excel文件中提取学习曲线数据
2. 单组预测分析：为单个数据组生成学习曲线预测
3. 两组对比分析：比较IR组和MR组的学习曲线差异

🔧 使用步骤：
1. 选择Excel源文件或直接指定CSV数据文件
2. 配置分析参数（模式、训练次数等）
3. 点击"开始分析"按钮执行分析
4. 在可视化标签页查看图表结果
5. 在分析结果标签页查看详细数据

📊 分析模式说明：
• 单组预测分析：基于Wright学习曲线模型，为每组数据生成预测曲线
• 两组对比分析：计算两组数据的平均学习曲线并进行对比分析

💡 提示：
• 支持中文文件名和中文数据
• 结果自动保存为PNG图片和CSV数据文件
• 可以自定义图表标题和训练次数范围

❓ 技术支持：
如遇到问题，请检查：
1. 数据文件格式是否正确
2. 是否已安装所有依赖包
3. 文件路径是否包含特殊字符
        """
        
        help_label = tk.Label(help_window,
                             text=help_text,
                             font=('Microsoft YaHei UI', 10),
                             justify='left',
                             bg='white')
        help_label.pack(fill='both', expand=True, padx=20, pady=20)
    
    def browse_excel_file(self):
        """浏览Excel文件"""
        file_path = filedialog.askopenfilename(
            title="选择Excel文件",
            filetypes=[("Excel files", "*.xlsx *.xls"), ("All files", "*.*")]
        )
        if file_path:
            self.excel_path_var.set(file_path)
            self.load_excel_sheets()
    
    def browse_csv_file(self, var):
        """浏览CSV文件"""
        file_path = filedialog.askopenfilename(
            title="选择CSV文件",
            filetypes=[("CSV files", "*.csv"), ("All files", "*.*")]
        )
        if file_path:
            var.set(file_path)
    
    def load_excel_sheets(self):
        """加载Excel工作表列表"""
        excel_path = self.excel_path_var.get()
        if not excel_path or not os.path.exists(excel_path):
            return
        
        try:
            self.update_status("正在读取Excel文件...")
            sheets = pd.read_excel(excel_path, sheet_name=None)
            sheet_names = list(sheets.keys())
            self.sheet_combo['values'] = sheet_names
            if sheet_names:
                self.sheet_combo.set(sheet_names[0])
            self.update_status(f"成功加载 {len(sheet_names)} 个工作表")
        except Exception as e:
            messagebox.showerror("错误", f"读取Excel文件失败：{str(e)}")
            self.update_status("Excel文件读取失败")
    
    def extract_excel_data(self):
        """提取Excel数据"""
        excel_path = self.excel_path_var.get()
        sheet_name = self.sheet_var.get()
        
        if not excel_path or not os.path.exists(excel_path):
            messagebox.showerror("错误", "请先选择有效的Excel文件")
            return
        
        if not sheet_name:
            messagebox.showerror("错误", "请选择工作表")
            return
        
        try:
            self.update_status("正在提取数据...")
            output_csv = f"{sheet_name}.csv"
            extract_groups_to_csv(excel_path, sheet_name, output_csv)
            
            messagebox.showinfo("成功", f"数据已成功提取到 {output_csv}")
            self.update_status(f"数据提取完成：{output_csv}")
            
            # 自动设置文件路径
            if "IR" in sheet_name.upper():
                self.ir_path_var.set(output_csv)
            elif "MR" in sheet_name.upper():
                self.mr_path_var.set(output_csv)
                
        except Exception as e:
            messagebox.showerror("错误", f"数据提取失败：{str(e)}")
            self.update_status("数据提取失败")
    
    def preview_data(self):
        """预览数据"""
        # 简单实现，显示当前设置的文件信息
        ir_path = self.ir_path_var.get()
        mr_path = self.mr_path_var.get()
        
        info = f"当前文件设置：\nIR组: {ir_path}\nMR组: {mr_path}\n\n"
        
        if os.path.exists(ir_path):
            info += f"✅ IR组文件存在\n"
        else:
            info += f"❌ IR组文件不存在\n"
            
        if os.path.exists(mr_path):
            info += f"✅ MR组文件存在\n"
        else:
            info += f"❌ MR组文件不存在\n"
        
        messagebox.showinfo("数据预览", info)
    
    def preview_csv_data(self, data_type):
        """预览CSV数据"""
        if data_type == 'ir':
            file_path = self.ir_path_var.get()
        else:
            file_path = self.mr_path_var.get()
        
        if not file_path or not os.path.exists(file_path):
            messagebox.showerror("错误", f"文件不存在：{file_path}")
            return
        
        try:
            self.update_status(f"正在加载{data_type.upper()}组数据...")
            data_groups = read_data_from_csv(file_path)
            
            # 清空当前显示
            self.clear_data_preview()
            
            # 设置列
            if data_groups:
                max_cols = max(len(group) for group in data_groups)
                columns = [f"数据点{i+1}" for i in range(max_cols)]
                
                self.data_tree['columns'] = columns
                self.data_tree['show'] = 'tree headings'
                
                # 设置列标题
                self.data_tree.heading('#0', text='组别', anchor='w')
                self.data_tree.column('#0', width=80)
                
                for col in columns:
                    self.data_tree.heading(col, text=col, anchor='center')
                    self.data_tree.column(col, width=80)
                
                # 插入数据
                for i, group in enumerate(data_groups):
                    values = group + [''] * (len(columns) - len(group))
                    self.data_tree.insert('', 'end', text=f'第{i+1}组', values=values)
            
            self.update_status(f"{data_type.upper()}组数据加载完成，共{len(data_groups)}组")
            
        except Exception as e:
            messagebox.showerror("错误", f"数据加载失败：{str(e)}")
            self.update_status("数据加载失败")
    
    def clear_data_preview(self):
        """清空数据预览"""
        for item in self.data_tree.get_children():
            self.data_tree.delete(item)
        self.data_tree['columns'] = ()
    
    def clear_results(self):
        """清空结果"""
        self.init_empty_plot()
        self.results_text.config(state='normal')
        self.results_text.delete('1.0', 'end')
        self.results_text.insert('1.0', "结果已清空。")
        self.results_text.config(state='disabled')
        self.update_status("结果已清空")
    
    def run_analysis(self):
        """运行分析"""
        # 禁用按钮并显示进度条
        self.analyze_btn.config(state='disabled')
        self.progress_bar.pack(fill='x', padx=15, pady=5)
        self.progress_var.set(0)
        
        # 在新线程中运行分析
        threading.Thread(target=self._analysis_thread, daemon=True).start()
    
    def _analysis_thread(self):
        """分析线程"""
        try:
            mode = self.analysis_mode.get()
            max_training = self.max_training_var.get()
            title = self.chart_title_var.get()
            
            self.root.after(0, lambda: self.update_status("正在分析数据..."))
            self.root.after(0, lambda: self.progress_var.set(20))
            
            if mode == "single":
                # 单组分析 - 这里简化使用IR组数据
                csv_file_path = self.ir_path_var.get()
                
                if not csv_file_path or not os.path.exists(csv_file_path):
                    self.root.after(0, lambda: messagebox.showerror("错误", f"文件不存在：{csv_file_path}"))
                    return
                
                data_groups = read_data_from_csv(csv_file_path)
                if not data_groups:
                    self.root.after(0, lambda: messagebox.showerror("错误", "未找到有效数据"))
                    return
                
                self.root.after(0, lambda: self.progress_var.set(50))
                
                if not title:
                    title = f"{os.path.splitext(os.path.basename(csv_file_path))[0]}学习曲线预测"
                
                # 执行分析
                result = plot_learning_curves(
                    data_groups=data_groups,
                    csv_file_path=csv_file_path,
                    max_training=max_training,
                    title=title,
                    save_csv=True,
                    save_plot=True
                )
                
                self.root.after(0, lambda: self.progress_var.set(80))
                self.root.after(0, lambda: self._update_single_plot(result, title, max_training))
                
            else:
                # 对比分析
                ir_path = self.ir_path_var.get()
                mr_path = self.mr_path_var.get()
                
                if not title:
                    title = "IR组与MR组平均学习曲线对比"
                
                self.root.after(0, lambda: self.progress_var.set(50))
                
                result = plot_average_learning_curves(
                    ir_csv_path=ir_path,
                    mr_csv_path=mr_path,
                    max_training=max_training,
                    title=title,
                    save_csv=True,
                    save_plot=True
                )
                
                self.root.after(0, lambda: self.progress_var.set(80))
                self.root.after(0, lambda: self._update_compare_plot(result, title, max_training))
            
            self.root.after(0, lambda: self.progress_var.set(100))
            self.root.after(0, lambda: self.update_status("分析完成"))
            self.root.after(0, lambda: messagebox.showinfo("完成", "数据分析完成！"))
            
        except Exception as e:
            self.root.after(0, lambda: messagebox.showerror("错误", f"分析失败：{str(e)}"))
            self.root.after(0, lambda: self.update_status("分析失败"))
        finally:
            self.root.after(0, lambda: self.analyze_btn.config(state='normal'))
            self.root.after(0, lambda: self.progress_bar.pack_forget())
    
    def _update_single_plot(self, result, title, max_training):
        """更新单组分析图表"""
        if not result:
            return
        
        self.figure.clear()
        ax = self.figure.add_subplot(111)
        
        # 绘制各组曲线
        colors = plt.cm.tab10(np.linspace(0, 1, len(result['valid_groups'])))
        
        for i, (prediction, group_info) in enumerate(zip(result['predictions'], result['valid_groups'])):
            group_num, y1, LR = group_info
            x_values = result['x_values']
            
            ax.plot(x_values, prediction, color=colors[i], linewidth=1.5,
                   label=f'组 {group_num} (y1={y1:.2f}, LR={LR:.4f})')
        
        ax.set_title(title, fontsize=14, fontweight='bold')
        ax.set_xlabel("训练次数 (x)", fontsize=12)
        ax.set_ylabel("分数", fontsize=12)
        ax.grid(True, linestyle="--", alpha=0.7)
        ax.set_xticks(np.arange(0, max_training + 1, 5))
        ax.legend(loc='best')
        ax.set_ylim(bottom=None, top=100)
        
        self.figure.tight_layout()
        self.canvas.draw()
        
        # 更新结果文本
        self._update_results_text(result, "single")
        
        # 切换到可视化标签页
        self.notebook.select(0)
    
    def _update_compare_plot(self, result, title, max_training):
        """更新对比分析图表"""
        if not result:
            return
        
        self.figure.clear()
        ax = self.figure.add_subplot(111)
        
        colors = ['#1f77b4', '#ff7f0e']
        labels = ['IR组', 'MR组']
        
        for i, (group_name, color, label) in enumerate(zip(['ir组', 'mr组'], colors, labels)):
            if group_name in result:
                group_data = result[group_name]
                x_values = np.array(group_data['x_values'])
                avg_predictions = np.array(group_data['average_predictions'])
                std_predictions = np.array(group_data['std_predictions'])
                
                ax.plot(x_values, avg_predictions, color=color, linewidth=2.5,
                       label=f'{label}平均曲线 (n={group_data["valid_count"]})', 
                       marker='o', markersize=4)
                
                ax.fill_between(x_values,
                               avg_predictions - std_predictions,
                               avg_predictions + std_predictions,
                               color=color, alpha=0.2,
                               label=f'{label}标准差范围')
        
        ax.set_title(title, fontsize=14, fontweight='bold')
        ax.set_xlabel("训练次数 (x)", fontsize=12)
        ax.set_ylabel("分数", fontsize=12)
        ax.grid(True, linestyle="--", alpha=0.7)
        ax.set_xticks(np.arange(0, max_training + 1, 5))
        ax.legend(loc='best')
        ax.set_ylim(bottom=None, top=100)
        
        self.figure.tight_layout()
        self.canvas.draw()
        
        # 更新结果文本
        self._update_results_text(result, "compare")
        
        # 切换到可视化标签页
        self.notebook.select(0)
    
    def _update_results_text(self, result, analysis_type):
        """更新结果文本"""
        self.results_text.config(state='normal')
        self.results_text.delete('1.0', 'end')
        
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        
        if analysis_type == "single" and result:
            text = f"单组预测分析结果\n"
            text += f"分析时间: {timestamp}\n"
            text += f"=" * 50 + "\n\n"
            text += f"有效组数: {len(result['valid_groups'])}\n"
            text += f"训练次数范围: 1 - {len(result['x_values'])}\n\n"
            
            text += "各组详细信息:\n"
            for i, group_info in enumerate(result['valid_groups']):
                group_num, y1, LR = group_info
                text += f"  组 {group_num}: 初始分数={y1:.2f}, 学习率={LR:.4f}\n"
            
            text += "\n预测数据已保存为CSV文件，图表已保存为PNG文件。"
            
        elif analysis_type == "compare" and result:
            text = f"两组对比分析结果\n"
            text += f"分析时间: {timestamp}\n"
            text += f"=" * 50 + "\n\n"
            
            for group_name in ['ir组', 'mr组']:
                if group_name in result:
                    group_data = result[group_name]
                    text += f"{group_name.upper()}:\n"
                    text += f"  有效样本数: {group_data['valid_count']}\n"
                    text += f"  平均起始分数: {group_data['average_predictions'][0]:.2f}\n"
                    text += f"  平均结束分数: {group_data['average_predictions'][-1]:.2f}\n"
                    text += f"  分数提升: {group_data['average_predictions'][-1] - group_data['average_predictions'][0]:.2f}\n\n"
            
            text += "对比数据已保存为CSV文件，图表已保存为PNG文件。"
        else:
            text = "分析失败或无有效结果。"
        
        self.results_text.insert('1.0', text)
        self.results_text.config(state='disabled')
    
    def init_empty_plot(self):
        """初始化空图表"""
        self.figure.clear()
        ax = self.figure.add_subplot(111)
        
        ax.text(0.5, 0.5, '📊\n\n暂无数据\n请先进行数据分析', 
               horizontalalignment='center', verticalalignment='center',
               transform=ax.transAxes, fontsize=16, 
               color='#757575')
        
        ax.set_xlim(0, 1)
        ax.set_ylim(0, 1)
        ax.axis('off')
        
        self.canvas.draw()
    
    def save_plot(self):
        """保存图表"""
        file_path = filedialog.asksaveasfilename(
            title="保存图表",
            defaultextension=".png",
            filetypes=[
                ("PNG files", "*.png"),
                ("PDF files", "*.pdf"),
                ("SVG files", "*.svg"),
                ("All files", "*.*")
            ]
        )
        if file_path:
            try:
                self.figure.savefig(file_path, dpi=300, bbox_inches='tight')
                messagebox.showinfo("成功", f"图表已保存到：{file_path}")
                self.update_status(f"图表已保存：{os.path.basename(file_path)}")
            except Exception as e:
                messagebox.showerror("错误", f"保存失败：{str(e)}")
    
    def refresh_plot(self):
        """刷新图表"""
        self.canvas.draw()
        self.update_status("图表已刷新")
    
    def show_plot_settings(self):
        """显示图表设置"""
        messagebox.showinfo("提示", "图表设置功能开发中...")
    
    def load_settings(self):
        """加载设置"""
        try:
            if os.path.exists('settings.json'):
                with open('settings.json', 'r', encoding='utf-8') as f:
                    settings = json.load(f)
                    self.current_theme = settings.get('theme', 'light')
                    if self.current_theme == 'dark':
                        self.theme_colors = MaterialColors.DARK
                    else:
                        self.theme_colors = MaterialColors.LIGHT
        except:
            pass
    
    def save_settings(self):
        """保存设置"""
        try:
            settings = {
                'theme': self.current_theme,
                'last_ir_file': self.ir_path_var.get(),
                'last_mr_file': self.mr_path_var.get(),
                'max_training': self.max_training_var.get()
            }
            with open('settings.json', 'w', encoding='utf-8') as f:
                json.dump(settings, f, ensure_ascii=False, indent=2)
        except:
            pass


def main():
    """主函数"""
    root = tk.Tk()
    
    # 设置DPI感知（Windows）
    try:
        from ctypes import windll
        windll.shcore.SetProcessDpiAwareness(1)
    except:
        pass
    
    app = LearningCurveAnalyzer(root)
    
    # 程序退出时保存设置
    def on_closing():
        if hasattr(app, 'save_settings'):
            app.save_settings()
        root.destroy()
    
    root.protocol("WM_DELETE_WINDOW", on_closing)
    root.mainloop()


if __name__ == "__main__":
    main()
